package client

import (
	"context"
	"fmt"
	"gitee.com/lsy007/emailclient/pb"
	"gitee.com/lsy007/library/request"
	"google.golang.org/grpc"
	"time"
)

type Header struct {
	RequestId string `json:"request_id"` // 请求唯一ID
	Region    string `json:"region"`     // 服务所在区域信息
	Server    string `json:"server"`     // 请求服务名称
	Other     string `json:"other"`      // 其他携带信息
}

type EmailRequest struct {
	// 请求头
	Header *Header `json:"header"` // [必]
	// 基础信息
	Subject string      `json:"subject"`  // [必]邮件主题
	Type    string      `json:"type"`     // [必]text-纯文本/html-HTML内容
	Text    string      `json:"text"`     // text - 纯文本邮件内容
	Html    string      `json:"html"`     // html - HTML 邮件内容
	HtmlKey string      `json:"html_key"` // HTML 文件对应 S3 存储键值
	Attach  []*FileInfo `json:"attach"`   // 附件信息
	Region  string      `json:"region"`   // S3 资源所属区域，cn/us/eu
	Bucket  string      `json:"bucket"`   // S3 存储桶名称
	// 发件人信息
	FromName     string `json:"from_name"`     // [必]发件人名称
	FromEmail    string `json:"from_email"`    // [必]发件人邮箱账号
	FromPassword string `json:"from_password"` // [必]发件客户端授权密码
	// 收件人信息
	Tos []string `json:"tos"` // [必]收件人账号
	Cc  []string `json:"cc"`  // 抄送人账号
	Bcc int64    `json:"bcc"` // 是否邮件密送，0-默认/1-否/2-是，多账号推送时默认邮件密送
}

type FileInfo struct {
	Key  string `json:"key"`  // 附件文件对应 S3 的 KEY 值
	Name string `json:"name"` // 附件文件名称，包含文件后缀
}

type EmailResponse struct {
	Status string `json:"status"` // 响应状态，success/fail
	Msg    string `json:"msg"`    // 错误信息
}

// Grpc 发送邮件
// @param param 请求参数内容地址指针
// @param addr 请求服务地址，如 127.0.0.1:6032
func GrpcSendMail(param *EmailRequest, addr string, ttl ...int) (reply *EmailResponse, err error) {
	// 1. 新建 grpc 连接
	conn, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		return reply, err
	}
	defer conn.Close() // 退出时关闭链接
	// 2. 调用 protobuf 生成的 *.pb.go 中的 *Client 方法创建客户端
	client := pb.NewEmailServerClient(conn)
	// 3. 组装服务请求参数
	attach := make([]*pb.FileInfo, 0)
	for _, v := range param.Attach {
		attach = append(attach, &pb.FileInfo{Key: v.Key, Name: v.Name})
	}
	header := &pb.Header{
		RequestId: param.Header.RequestId,
		Region:    param.Header.Region,
		Server:    param.Header.Server,
		Other:     param.Header.Other,
	}
	// 4. 设置超时时间，调用 SendMail 方法发送邮件
	t := 60
	if len(ttl) > 0 {
		t = ttl[0]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(t)*time.Millisecond)
	defer cancel()
	res, err := client.SendMail(ctx, &pb.EmailRequest{
		Header:       header,
		Subject:      param.Subject,
		Type:         param.Type,
		Text:         param.Text,
		Html:         param.Html,
		HtmlKey:      param.HtmlKey,
		Attach:       attach,
		Region:       param.Region,
		Bucket:       param.Bucket,
		FromName:     param.FromName,
		FromEmail:    param.FromEmail,
		FromPassword: param.FromPassword,
		Tos:          param.Tos,
		Cc:           param.Cc,
		Bcc:          param.Bcc,
	})
	if err != nil {
		return reply, err
	}
	return &EmailResponse{Status: res.Status, Msg: res.Msg}, nil
}

// Grpc 发送邮件
// @param param 请求参数内容地址指针
// @param addr HTTP 请求服务地址，如 http://127.0.0.1:6030
// @param ttl 请求过期时间
func HttpSendMail(param *EmailRequest, addr string, ttl ...int) (reply *EmailResponse, err error) {
	// 1. 声明响应结构体
	res := EmailResponse{}
	// 2. 组装 http 请求客户端
	t := 60
	if len(ttl) > 0 {
		t = ttl[0]
	}
	httpRequest := request.HttpRequest{
		Method: request.POST,
		Url:    fmt.Sprintf("%s/sendmail", addr),
		Args:   param,
		Ttl:    t,
		Reply:  &res,
	}
	// 3. 执行 http 请求
	if _, err := httpRequest.HttpHandle(); err != nil {
		return reply, err
	}
	return &res, nil
}
